package com.example.userservice.service.impl;

import com.example.userservice.config.JwtConfig;
import com.example.userservice.dto.UserDTO;
import com.example.userservice.entity.User;
import com.example.userservice.feign.PermissionService;
import com.example.userservice.feign.LoggingService;
import com.example.userservice.mapper.UserMapper;
import com.example.userservice.service.UserService;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final RabbitTemplate rabbitTemplate;
    private final PermissionService permissionService;
    private final LoggingService loggingService;
    private final JwtConfig jwtConfig;
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Override
    @Transactional
    public UserDTO register(UserDTO userDTO) {
        // Check if username or email already exists
        if (userMapper.findByUsername(userDTO.getUsername()) != null) {
            throw new RuntimeException("用户名已经存在");
        }
        if (userMapper.findByEmail(userDTO.getEmail()) != null) {
            throw new RuntimeException("Email已经存在");
        }

        // Create new user
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);

        user.setUserId(Math.abs(UUID.randomUUID().getMostSignificantBits()));
        user.setPassword(passwordEncoder.encode(userDTO.getPassword()));

        userMapper.insert(user);
        // int i = 10/0;
        // Bind default role
        permissionService.bindDefaultRole(user.getUserId());

        // Send log message
        Map<String, Object> logMessage = new HashMap<>();
        logMessage.put("userId", user.getUserId());
        logMessage.put("action", "REGISTER");
        logMessage.put("details", "User registered successfully");
        logMessage.put("ip", "127.0.0.1");
        rabbitTemplate.convertAndSend("user.logs", logMessage);

        // Convert to DTO and return
        BeanUtils.copyProperties(user, userDTO);
        userDTO.setPassword(null); // Don't return password
        return userDTO;
    }

    @Override
    public String login(String username, String password) {
        User user = userMapper.findByUsername(username);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // Get user role
        String roleCode = permissionService.getUserRoleCode(user.getUserId());

        // Generate JWT token
        return "Bearer " + jwtConfig.generateToken(user.getUserId(), username, roleCode);
    }

    @Override
    public UserDTO getUserInfo(Long userId, String roleCode, Long currentUserId) {
        User user = userMapper.findById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 权限判断
        if ("super_admin".equals(roleCode)) {
            // 可查任意
        } else if ("admin".equals(roleCode)) {
            if (userId.equals(currentUserId)) {
                // 管理员查自己
            } else {
                String targetRole = permissionService.getUserRoleCode(userId);
                if (!"user".equals(targetRole)) {
                    throw new RuntimeException("无权限访问该用户信息");
                }
            }
        } else {
            if (!userId.equals(currentUserId)) {
                throw new RuntimeException("无权限访问他人信息");
            }
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        userDTO.setPassword(null);
        return userDTO;
    }

    @Override
    public PageInfo<UserDTO> getUserList(int pageNum, int pageSize, String roleCode, Long currentUserId) {
        List<User> users;
        if ("super_admin".equals(roleCode)) {
            users = userMapper.findAll();
        } else if ("admin".equals(roleCode)) {
            users = userMapper.findByRole("user");
        } else {
            User user = userMapper.findById(currentUserId);
            users = user == null ? Collections.emptyList() : Collections.singletonList(user);
        }
        List<UserDTO> userDTOs = users.stream().map(user -> {
            UserDTO dto = new UserDTO();
            BeanUtils.copyProperties(user, dto);
            dto.setPassword(null);
            return dto;
        }).collect(Collectors.toList());
        return new PageInfo<>(userDTOs);
    }

    @Override
    @Transactional
    public UserDTO updateUser(Long userId, UserDTO userDTO, String roleCode, Long currentUserId) {
        User user = userMapper.findById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 查询目标用户角色
        String targetRole = permissionService.getUserRoleCode(userId);
        // 权限判断
        if ("super_admin".equals(roleCode)) {
            // 超管可操作所有
        } else if ("admin".equals(roleCode)) {
            if ("super_admin".equals(targetRole) || "admin".equals(targetRole)) {
                // 管理员不能操作超管和其他管理员
                if (!userId.equals(currentUserId)) {
                    throw new RuntimeException("管理员只能操作自己和普通用户");
                }
            }
        } else if ("user".equals(roleCode)) {
            if (!userId.equals(currentUserId)) {
                throw new RuntimeException("普通用户只能操作自己");
            }
        } else {
            throw new RuntimeException("未知角色，无权限");
        }
        // 更新用户信息
        if (userDTO.getUsername() != null)
            user.setUsername(userDTO.getUsername());
        if (userDTO.getPassword() != null)
            user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        if (userDTO.getEmail() != null)
            user.setEmail(userDTO.getEmail());
        if (userDTO.getPhone() != null)
            user.setPhone(userDTO.getPhone());
        userMapper.update(user);
        // 日志
        Map<String, Object> logMessage = new HashMap<>();
        logMessage.put("userId", user.getUserId());
        logMessage.put("action", "UPDATE_USER");
        logMessage.put("details", "User information updated");
        rabbitTemplate.convertAndSend("user.logs", logMessage);
        BeanUtils.copyProperties(user, userDTO);
        userDTO.setPassword(null);
        return userDTO;
    }

    @Override
    @Transactional
    public void resetPassword(Long userId, String newPassword, String roleCode, Long currentUserId) {
        User user = userMapper.findById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 查询目标用户角色
        String targetRole = permissionService.getUserRoleCode(userId);
        // 权限判断
        if ("super_admin".equals(roleCode)) {
            // 超管可操作所有
        } else if ("admin".equals(roleCode)) {
            if ("super_admin".equals(targetRole) || "admin".equals(targetRole)) {
                // 管理员不能操作超管和其他管理员
                if (!userId.equals(currentUserId)) {
                    throw new RuntimeException("管理员只能重置自己和普通用户的密码");
                }
            }
        } else if ("user".equals(roleCode)) {
            if (!userId.equals(currentUserId)) {
                throw new RuntimeException("普通用户只能重置自己的密码");
            }
        } else {
            throw new RuntimeException("未知角色，无权限");
        }
        user.setPassword(passwordEncoder.encode(newPassword));
        userMapper.update(user);
        // 日志
        Map<String, Object> logMessage = new HashMap<>();
        logMessage.put("userId", user.getUserId());
        logMessage.put("action", "RESET_PASSWORD");
        logMessage.put("details", "User password reset");
        rabbitTemplate.convertAndSend("user.logs", logMessage);
    }

    /**
     * 分布式事务示例：用户注册时同时创建权限记录
     * 如果任何一步失败，整个事务回滚
     */
    @GlobalTransactional(name = "user-register-transaction", rollbackFor = Exception.class)
    public void registerUserWithTransaction(UserDTO userDTO) {
        try {
            User user = new User();
            BeanUtils.copyProperties(userDTO, user); // 先拷贝
            user.setUserId(UUID.randomUUID().getLeastSignificantBits()); // 再赋值userId，防止被覆盖

            System.out.println("user_id: " + user.getUserId()); // 调试用，确保不为null

            userMapper.insert(user);
            log.info("用户创建成功: {}", user.getUsername());

            // 2. 调用权限服务创建用户角色关系（模拟分布式调用）
            // 这里会通过Feign调用permission-service
            // 如果权限服务创建失败，整个事务会回滚
            permissionService.createUserRole(user.getUserId(), "user");
            log.info("用户角色关系创建成功: {}", user.getUserId());

            // 3. 记录操作日志（模拟分布式调用）
            // 如果日志服务失败，整个事务会回滚
            loggingService.logOperation("USER_REGISTER", user.getUserId(),
                    "用户注册: " + user.getUsername());
            log.info("操作日志记录成功");
            Thread.sleep(1000); // 模拟网络延迟
        } catch (Exception e) {
            log.error("用户注册事务失败，开始回滚: {}", e.getMessage());
            throw new RuntimeException("用户注册失败", e);
        }
    }

    /**
     * 普通事务示例：仅在本服务内的事务
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateUserWithLocalTransaction(UserDTO userDTO) {
        User user = userMapper.findById(userDTO.getUserId());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        user.setEmail(userDTO.getEmail());
        userMapper.update(user);

        // 如果这里抛出异常，只有用户更新会回滚
        if (userDTO.getEmail() != null && userDTO.getEmail().contains("test")) {
            throw new RuntimeException("测试回滚");
        }
    }
}
